/*-----------------------------------*
 | Copyright (c) Agoston Roth, 2010. |               |
 *-----------------------------------*/

/*-------------*
 | Description |
 *-------------*----------------------------------------------------------------------------------------------*
 | Class SplineInformation is a column matrix that stores the r-th (r = 0, 1,...) order derivatives of any 2- |
 | and 3-dimensional approximating spline at a given knot value.                                              |
 |                                                                                                            |
 | The abstract class ApproximatingSpline can be used as a base class for any type of curve which is based on |
 | an approximation method (like Bezier, NURBS, or cyclic curves). The derived class needs to implement the   |
 | abstract methods                                                                                           |
 |                                                                                                            |
 |      virtual GLboolean BlendingFunctionValues(GLdouble knot, RowMatrix<GLdouble>& values) const = 0;       |
 |      virtual GLboolean CalculateAllInformation(GLdouble knot, SplineInformation& data) const = 0;          |
 |                                                                                                            |
 | in order to be able to generate the shape of the curve and to solve the curve interpolation problem.       |
 |                                                                                                            |
 | It is possible that in some cases the curve interpolation problem can be solved more efficiently than      |
 | using the method                                                                                           |
 |                                                                                                            |
 |       virtual GLboolean UpdateControlPointsForInterpolation(const ColumnMatrix<GLdouble>& knot_vector,     |
 |                                                             const ColumnMatrix<DCoordinate>& data_points); |
 |                                                                                                            |
 | which is based on LU decomposition. In suchlike cases the derived class can redeclare and implement this   |
 | virtual method in order to provide a more efficient solution to this problem.                              |
 |                                                                                                            |
 | Notice that the degree elevation/reduction problem is not implemented by this class, because, in general,  |
 | besides the number of the control points (i.e. of the basis functions) these operations may also depend on |
 | other parameters which are unknown in advance (e.g. consider the case of NURBS curves).                    |
 *------------------------------------------------------------------------------------------------------------*/

#pragma once

#include <vector>
#include <GL/glew.h>
#include "DCoordinates.h"
#include "GenericCurves.h"
#include "Matrices.h"

namespace cagd
{
    class SplineInformation: public ColumnMatrix<DCoordinate>
    {
    public:
        SplineInformation(GLuint maximum_order_of_derivatives = 2);
        GLvoid LoadNullVectors();
    };

    class ApproximatingSpline
    {
    protected:
        GLboolean                 _is_closed;
        GLuint                    _vbo_control_polygon;
        GLenum                    _usage_flag_control_polygon;
        GLdouble                  _t_min, _t_max;
        ColumnMatrix<DCoordinate> _control_point;

    public:
        // special constructor
        ApproximatingSpline(GLdouble t_min, GLdouble t_max, GLuint control_point_count, GLboolean is_closed = false, GLenum usage_flag_control_polygon = GL_STATIC_DRAW);

        // copy constructor
        ApproximatingSpline(const ApproximatingSpline& spline);

        // assignment operator
        ApproximatingSpline& operator =(const ApproximatingSpline& rhs);

        // set or get domain
        GLvoid SetDomain(GLdouble t_min, GLdouble t_max);
        GLvoid GetDomain(GLdouble& t_min, GLdouble& t_max) const;

        // set or get control point
        GLboolean SetControlPoint(GLuint index, GLdouble x, GLdouble y, GLdouble z = 0.0);
        GLboolean SetControlPoint(GLuint index, const DCoordinate& p);
        GLboolean GetControlPoint(GLuint index, DCoordinate& p) const;

        // abstract methods
        virtual GLboolean BlendingFunctionValues(GLdouble knot, RowMatrix<GLdouble>& values) const = 0;
        virtual GLboolean CalculateAllInformation(GLdouble knot, SplineInformation& data) const = 0;

        // generate curve
        GLboolean GenerateShape(GLuint division_point_count, GenericCurve& shape) const;
        GLboolean GenerateArc(GLdouble t_min, GLdouble t_max, GLuint division_point_count, GenericCurve& arc) const;

        // assure interpolation
        virtual GLboolean UpdateControlPointsForInterpolation(const ColumnMatrix<GLdouble>& knot_vector, const ColumnMatrix<DCoordinate>& data_points);

        // handle vertex buffer object of control polygon
        GLvoid DeleteVertexBufferObjectOfControlPolygon();
        GLboolean RenderControlPolygon(GLenum render_mode = GL_LINE_STRIP) const;
        GLboolean UpdateVertexBufferObjectOfControlPolygon(GLenum usage_flag = GL_STATIC_DRAW);

        // destructor
        virtual ~ApproximatingSpline();
    };
}
